package com.css.fxfzdzzh.modules.surfaceRupture.service.impl;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.css.fxfzdzzh.base.dict.repository.DictItemRepository;
import com.css.fxfzdzzh.base.dict.viewobjects.DictEntityVo;
import com.css.fxfzdzzh.base.response.RestResponse;
import com.css.fxfzdzzh.constants.YNEnum;
import com.css.fxfzdzzh.modules.drill.service.DrillService;
import com.css.fxfzdzzh.modules.eqLandslide.count.entity.HistoricalSurfaceEntity;
import com.css.fxfzdzzh.modules.eqLandslide.lawAnalysis.repository.LawAnalysisRepository;
import com.css.fxfzdzzh.modules.surfaceRupture.entity.*;
import com.css.fxfzdzzh.modules.surfaceRupture.param.PageQueryParam;
import com.css.fxfzdzzh.modules.surfaceRupture.repository.SurfaceRuptureRepository;
import com.css.fxfzdzzh.modules.surfaceRupture.service.SurfaceRuptureService;
import com.css.fxfzdzzh.modules.surfaceRupture.vo.ParamVO;
import com.css.fxfzdzzh.modules.surfaceRupture.vo.SurfaceRuptureVO;
import com.css.fxfzdzzh.util.CreateGson;
import com.css.fxfzdzzh.util.PlatformObjectUtils;
import com.css.fxfzdzzh.util.UUIDGenerator;
import com.css.fxfzdzzh.web.PlatformSessionContext;
import com.css.fxfzdzzh.zcpt.sys.entity.SUser;
import com.css.fxfzdzzh.zcpt.sys.service.SUserService;
import com.css.fxfzdzzh.zcpt.sys.service.SysAreaService;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.apache.commons.lang3.StringUtils;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.util.GeometricShapeFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author Dbj
 * @date 2023年04月08日  13:49
 */
@Service
public class SurfaceRuptureServiceImpl implements SurfaceRuptureService {

    @Resource
    SurfaceRuptureRepository surfaceRuptureRepository;
    @Resource
    DrillService drillService;
    @Resource
    SUserService sUserService;

    @Resource
    SysAreaService sysAreaService;

    @Resource
    JdbcTemplate jdbcTemplate;

    @Resource
    LawAnalysisRepository lawAnalysisRepository;

    @Value("${basicData.url}")
    public String basicDataUrl;
    /**
     * 数据源
     * 10.19.41.111
     */
    @Value("${spring.datasource.url}")
    private String url = "";
    @Value("${spring.datasource.username}")
    private String name = "";
    @Value("${spring.datasource.password}")
    private String pwd = "";

    @Resource
    DictItemRepository dictItemRepository;

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void evaluate(SurfaceRuptureVO vo) throws Exception{
//        String userId = "80cd530287e54c6788925adf2dfc9da1";
//        String userJson = sUserService.getSUser(userId);
//        SUser sUser = CreateGson.createGson().fromJson(userJson, SUser.class);
//
//        //计算拼接经纬度
//        Map<String, BigDecimal> map = getLongitudeAndLatitude(vo);
//        BigDecimal longitude = map.get("longitude");
//        BigDecimal latitude = map.get("latitude");
////        BigDecimal longitude = new BigDecimal("114.818714");
////        BigDecimal latitude =  new BigDecimal("40.3392887");
//
//
//
//        //根据经纬度查询大致的省份信息
//        String msg = this.queryProvinceCityCountyNameStringByLonLat(longitude.toString(), latitude.toString());
//        String province = "";
//        String city = "";
//        String county = "";
//        if(StringUtils.isNotBlank(msg)){
//            String[] split = msg.split(",");
//            province = split[0];
//            if(split.length==2){
//                city = split[1];
//            }else if(split.length==3){
//                city = split[1];
//                county = split[2];
//            }
//        }
//        if(StringUtils.isBlank(province)){
//            throw new RuntimeException("根据经纬度无法查询到地域信息");
//        }
//        String idByCondition = sysAreaService.getIdByCondition(province, city, county);
//        String provinceId = "";
//        String cityId = "";
//        String countyId = "";
//        if(StringUtils.isNotBlank(idByCondition)){
//            String[] split = idByCondition.split(",");
//            if(split.length==1){
//                provinceId = split[0];
//            }else if(split.length==2){
//                provinceId = split[0];
//                cityId = split[1];
//            }else{
//                provinceId = split[0];
//                cityId = split[1];
//                countyId = split[2];
//            }
//        }
//        //根据省份判断所属分区
//        String subregion = getSubregionByProvince(province);
//        String partition = getPartitionByProvince(province);
//        //断层性质
//        Integer faultProperties = vo.getFaultProperties();
//        BiMap<String, String> bitMap = buildFaultProperties();
//        //如果断层性质为空，那就分别计算走滑断层、逆断层、逆走滑、正断层、正走滑五种
//        Set<String> faultPropertiesList = new HashSet<>(5);
//        if(faultProperties!=null){
//            faultPropertiesList = bitMap.values();
//        }else{
//            faultPropertiesList.add(bitMap.get(faultProperties));
//        }
//        List<SurfaceRupture> list = new ArrayList<>(5);
//
//        String maxParentNum = "";
//        synchronized (this){
//            maxParentNum = getTaskCode(surfaceRuptureRepository.getMaxNum());
//            for (String rupture : faultPropertiesList) {
//                //计算地表破裂长度
//                BigDecimal ruptureLength = getRuptureLength(rupture,subregion,vo.getEarthQuakeLevel());
//                //计算同震位移
//                BigDecimal displacement = getDisplacement(rupture,subregion,vo.getEarthQuakeLevel());
//                //计算地表破裂宽度
//                BigDecimal ruptureWidth = getRuptureWidth(partition,vo.getEarthQuakeLevel());
//                //计算地表破裂长度区间
//                String lengthSection = getCalculateLengthSection(ruptureLength,vo.getEarthQuakeLevel());
//                SurfaceRupture surfaceRupture = new SurfaceRupture();
//                BeanUtils.copyProperties(vo,surfaceRupture);
//                surfaceRupture.setDsrId(UUIDGenerator.getUUID()).setEvaluateUser(userId).setEvaluateUserName(sUser.getUserName()).setNum(maxParentNum)
//                        .setEvaluateTime(new Date()).setDataSource("1").setLongitude(longitude).setLatitude(latitude).setRuptureLength(ruptureLength).setFaultProperties(bitMap.inverse().get(rupture))
//                        .setDisplacement(displacement).setRuptureWidth(ruptureWidth).setLengthSection(lengthSection).setProvince(province).setFaultVersion(vo.getFaultVersion())
//                        .setCity(city).setCounty(county).setProvinceId(provinceId).setCityId(cityId).setCountyId(countyId).setDelFlag(YNEnum.N.toString()).setEarthQuakeTime(new Date()).setSourceFrom("2");
//                list.add(surfaceRupture);
//            }
//            surfaceRuptureRepository.evaluate(list);
//        }
//        //发震构造评估
//        seismogenicStructureSstimate(longitude,latitude,vo.getFaultVersion(),maxParentNum);
//    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SurfaceRupture evaluate(String drsId) throws Exception{
        //101.88292907689107 23.65722218567909
//        BigDecimal longitude = new BigDecimal(101.88292907689107);
//        BigDecimal latitude = new BigDecimal(23.65722218567909);
        return createEvaluateResult(drsId);
    }

    private SurfaceRupture createEvaluateResult(String drsId) throws Exception {
        SurfaceRupture vo = surfaceRuptureRepository.getById(drsId);
        BigDecimal longitude = vo.getLongitude();
        BigDecimal latitude = vo.getLatitude();
        //保存最终符合条件的断层数据
        List<Fault> resultFaultList = new ArrayList<>();
        //根据省份判断所属分区
        String subregion = getSubregionByProvince(vo.getProvince());
        String partition = getPartitionByProvince(vo.getProvince());
        //查询字典获取数据
        Map<String, String> featureMap = getFeatureMap();
        if(featureMap==null || featureMap.values().size()==0){
            throw new RuntimeException("评估失败,请至字典项中维护断层性质");
        }
        //计算地表破裂宽度
        BigDecimal ruptureWidth = getRuptureWidth(partition,vo.getEarthQuakeLevel());
        //计算地表破裂长度
        BigDecimal ruptureLength = BigDecimal.ZERO;
        //计算同震位移
        BigDecimal displacement = BigDecimal.ZERO;
        //保存相同断层版本下所有断层名称相同的断层
        List<Fault> sameNameFaultList = new ArrayList<>();
        //
        Fault evaluateFault  = null;
        //根据经纬度获取25公里范围内的活断层数据
        List<Fault> kilometerFaultData = get25KilometerFaultData(longitude, latitude, vo.getFaultVersion());
        List<Fault> tempFaultList = new ArrayList<Fault>();
        //地表破裂带编号
        String maxParentNum = vo.getNum();
        if(PlatformObjectUtils.isNotEmpty(kilometerFaultData) && kilometerFaultData.size()>1){
            //筛选最新时代为Qh、Qh3、Qh2、Qp3、Qp32、Qp31的断层数据
            List<Fault> faultList = kilometerFaultData.stream().filter(fault -> {
                return getLatestActivePeriod().contains(fault.getLatestActivePeriod());
            }).collect(Collectors.toList());
            if(PlatformObjectUtils.isEmpty(faultList) || faultList.size()==0){
                throw new RuntimeException("评估未完成,获取不到最新时代为Qh、Qh3、Qh2、Qp3、Qp32、Qp31的断层数据无地表破裂带评估结果");
            }
            int size = faultList.size();
            if(size>1){
                //表示存在多条符合条件的断层数据
                faultList.forEach(fault -> {
                    //获取投影距离在3Km内的所有的断层数据
                    List<Fault> km3Fault = get3kmFault(fault, longitude, latitude, vo.getSourceDepth());
                    if((PlatformObjectUtils.isNotEmpty(km3Fault)&& km3Fault.size()>0)){
                        tempFaultList.addAll(km3Fault);
                    }
                });
                if(PlatformObjectUtils.isEmpty(tempFaultList) || tempFaultList.size()==0){
                    throw new RuntimeException("评估未完成,获取不到投影距离在3Km内的断层数据无地表破裂带评估结果");
                }
                //长度区间
                String lengthSection = "";
                //两者投影点距离在3km以内的断层数据还是有多条
                if(tempFaultList.size()>1){
                    // 遍历断层，分别到基础数据的jc_instrument_catalog（1970年以来小震目录）和jc_stratum_lithology（历史4
                    // 3/4以上强震目录）中获取到断层距离为3公里的小镇，判断断层附近的小镇数量哪个多就取哪个断层
                    // MULTILINESTRING((101.96971250482832 29.96109458854447,101.96900014733897
                    // 29.962479064257476,101.96861375002456 29.96376074296402,101.9686131151033
                    // 29.963763977825376,101.96829869502878 29.965366000440653))
                    Fault fault = getMostTownFault(tempFaultList);
                    evaluateFault = fault;
                    //获取相同名称的断层且断层长度之和在地表劈裂带区间范围的断层
                    sameNameFaultList.add(fault);
                    resultFaultList.add(fault);
                    //断层性质
                    String featureName = featureMap.get(fault.getFeature() + "");
                    //计算同震位移
                    displacement = getDisplacement(featureName,subregion,vo.getEarthQuakeLevel());
                    //计算地表破裂长度
                    ruptureLength = getRuptureLength(featureName,subregion,vo.getEarthQuakeLevel());
                    //计算地表破裂长度区间
                    lengthSection = getCalculateLengthSection(ruptureLength,vo.getEarthQuakeLevel());
                    //活断层可能是分段的，要获取其他的相同名称的断层
                    List<Fault> hashFaultList = listByNameExcludeId(fault.getDcName(),fault.getId(),vo.getFaultVersion());
                    if(PlatformObjectUtils.isNotEmpty(hashFaultList) && hashFaultList.size()>0){
                        sameNameFaultList.addAll(hashFaultList);
                    }
                    Map<Integer,Fault> resultFault = getData(fault,vo.getEarthQuakeLevel(),lengthSection,hashFaultList);
                    //最终的地表破裂带长度 是断层长度之和在上面区间范围内的所有断层的长度之和
                    //ruptureLength = BigDecimal.ZERO;
                    if(PlatformObjectUtils.isNotEmpty(resultFault)){
                        Iterator<Fault> iterator = resultFault.values().iterator();
                        while (iterator.hasNext()){
                            Fault next = iterator.next();
                            ruptureLength = ruptureLength.add(new BigDecimal(next.getJfLength()));
                            Fault tempFault = next;
                            //断层方向
                            tempFault.setSituation(getFaultSituation(featureName));
                            resultFaultList.add(tempFault);
                        }
                    }
                }else if(tempFaultList.size()==1){
                    Fault fault = tempFaultList.get(0);
                    evaluateFault = fault;
                    sameNameFaultList.add(fault);
                    resultFaultList.add(fault);
                    //断层性质
                    String featureName = featureMap.get(fault.getFeature() + "");
                    //计算同震位移
                    displacement = getDisplacement(featureName,subregion,vo.getEarthQuakeLevel());
                    //计算地表破裂长度
                    ruptureLength = getRuptureLength(featureName,subregion,vo.getEarthQuakeLevel());
                    //计算地表破裂长度区间
                    lengthSection = getCalculateLengthSection(ruptureLength,vo.getEarthQuakeLevel());
                    //获取相同名称的断层且断层长度之和在地表劈裂带区间范围的断层
                    //活断层可能是分段的，要获取其他的相同名称的断层
                    List<Fault> hashFaultList = listByNameExcludeId(fault.getDcName(),fault.getId(),vo.getFaultVersion());
                    if(PlatformObjectUtils.isNotEmpty(hashFaultList) && hashFaultList.size()>0){
                        sameNameFaultList.addAll(hashFaultList);
                    }
                    Map<Integer,Fault> resultFault = getData(fault,vo.getEarthQuakeLevel(),lengthSection,hashFaultList);
                    //最终的地表破裂带长度 是断层长度之和在上面区间范围内的
                    //ruptureLength = BigDecimal.ZERO;
                    if(PlatformObjectUtils.isNotEmpty(resultFault)){
                        Iterator<Fault> iterator = resultFault.values().iterator();
                        while (iterator.hasNext()){
                            Fault next = iterator.next();
                            ruptureLength = ruptureLength.add(new BigDecimal(next.getJfLength()));
                            Fault tempFault = next;
                            //断层方向
                            tempFault.setSituation(getFaultSituation(featureName));
                            resultFaultList.add(tempFault);
                        }
                    }
                }
                //保存地表破裂带区间范围内的断层
                if(resultFaultList.size()>0){
                    List<SurfaceRuptureFaultDisplacement> surfaceRuptureFaultDisplacements =  new ArrayList<>();
                    List<SurfaceRuptureFault> surfaceRuptureFaultList = new ArrayList<>();
                    for (Fault fault : resultFaultList) {
                        String id = UUIDGenerator.getUUID();
                        SurfaceRuptureFault surfaceRuptureFault = new SurfaceRuptureFault();
                        BeanUtils.copyProperties(fault,surfaceRuptureFault);
                        surfaceRuptureFault.setPreFault(PlatformObjectUtils.isNotEmpty(fault.getPreFault())?fault.getPreFault().getId():"");
                        surfaceRuptureFault.setPostFault(PlatformObjectUtils.isNotEmpty(fault.getPostFault())?fault.getPostFault().getId():"");
                        surfaceRuptureFault.setNum(maxParentNum);
                        surfaceRuptureFault.setCreateTime(new Date());
                        surfaceRuptureFault.setCreateUserId(PlatformObjectUtils.isNotEmpty(PlatformSessionContext.getUserID())?PlatformSessionContext.getUserID():"80cd530287e54c6788925adf2dfc9da1");
                        surfaceRuptureFault.setFaultId(fault.getId());
                        surfaceRuptureFault.setId(id);
                        surfaceRuptureFaultList.add(surfaceRuptureFault);
                        SurfaceRuptureFaultDisplacement surfaceRuptureFaultDisplacement = new SurfaceRuptureFaultDisplacement();
                        surfaceRuptureFaultDisplacement.setId(fault.getId());
                        surfaceRuptureFaultDisplacement.setNum(maxParentNum);
                        surfaceRuptureFaultDisplacement.setCenterGeom(fault.getCenterGeom());
                        surfaceRuptureFaultDisplacement.setSituation(fault.getSituation());
                        surfaceRuptureFaultDisplacement.setId(id);
                        surfaceRuptureFaultDisplacement.setFaultId(fault.getId());
                        surfaceRuptureFaultDisplacements.add(surfaceRuptureFaultDisplacement);
                    }
                    if(surfaceRuptureFaultList.size()>0){
                        surfaceRuptureRepository.batchSaveFault(surfaceRuptureFaultList);
                    }
                    if(surfaceRuptureFaultDisplacements.size()>0){
                        surfaceRuptureRepository.batchSaveFaultDisplacement(surfaceRuptureFaultDisplacements);
                    }
                }
            }else{
                //只有一条符合条件的断层数据
                Fault fault = faultList.get(0);
                resultFaultList.add(fault);
                evaluateFault = fault;
                sameNameFaultList.add(fault);
                //断层性质
                String featureName = featureMap.get(fault.getFeature() + "");
                //计算同震位移
                displacement = getDisplacement(featureName,subregion,vo.getEarthQuakeLevel());
                //计算地表破裂长度
                ruptureLength = getRuptureLength(featureName,subregion,vo.getEarthQuakeLevel());
                //计算地表破裂长度区间
                String lengthSection = getCalculateLengthSection(ruptureLength,vo.getEarthQuakeLevel());
                //活断层可能是分段的，要获取其他的相同名称的断层
                List<Fault> hashFaultList = listByNameExcludeId(fault.getDcName(),fault.getId(),vo.getFaultVersion());
                if(PlatformObjectUtils.isNotEmpty(hashFaultList) && hashFaultList.size()>0){
                    sameNameFaultList.addAll(hashFaultList);
                }
                Map<Integer,Fault> resultFault = getData(fault,vo.getEarthQuakeLevel(),lengthSection,hashFaultList);
                //最终的地表破裂带长度 是断层长度之和在上面区间范围内的
                //ruptureLength = BigDecimal.ZERO;
                if(PlatformObjectUtils.isNotEmpty(resultFault)){
                    Iterator<Fault> iterator = resultFault.values().iterator();
                    while (iterator.hasNext()){
                        Fault next = iterator.next();
                        ruptureLength = ruptureLength.add(new BigDecimal(next.getJfLength()));
                        Fault tempFault = next;
                        //断层方向
                        tempFault.setSituation(getFaultSituation(featureName));
                        resultFaultList.add(tempFault);
                    }
                }
                //保存地表破裂带区间范围内的断层
                if(resultFaultList.size()>0){
                    List<SurfaceRuptureFaultDisplacement> surfaceRuptureFaultDisplacements =  new ArrayList<>();
                    List<SurfaceRuptureFault> surfaceRuptureFaultList = new ArrayList<>();
                    for (Fault f : resultFaultList) {
                        String id = UUIDGenerator.getUUID();
                        SurfaceRuptureFault surfaceRuptureFault = new SurfaceRuptureFault();
                        BeanUtils.copyProperties(f,surfaceRuptureFault);
                        surfaceRuptureFault.setPreFault(PlatformObjectUtils.isNotEmpty(f.getPreFault())?f.getPreFault().getId():"");
                        surfaceRuptureFault.setPostFault(PlatformObjectUtils.isNotEmpty(f.getPostFault())?f.getPostFault().getId():"");
                        surfaceRuptureFault.setNum(maxParentNum);
                        surfaceRuptureFault.setCreateTime(new Date());
                        surfaceRuptureFault.setCreateUserId(PlatformObjectUtils.isNotEmpty(PlatformSessionContext.getUserID())?PlatformSessionContext.getUserID():"80cd530287e54c6788925adf2dfc9da1");
                        surfaceRuptureFault.setNum(maxParentNum);
                        surfaceRuptureFault.setFaultId(f.getId());
                        surfaceRuptureFault.setId(id);
                        surfaceRuptureFaultList.add(surfaceRuptureFault);
                        SurfaceRuptureFaultDisplacement surfaceRuptureFaultDisplacement = new SurfaceRuptureFaultDisplacement();
                        surfaceRuptureFaultDisplacement.setId(id);
                        surfaceRuptureFaultDisplacement.setFaultId(f.getId());
                        surfaceRuptureFaultDisplacement.setNum(maxParentNum);
                        surfaceRuptureFaultDisplacement.setCenterGeom(f.getCenterGeom());
                        surfaceRuptureFaultDisplacement.setSituation(f.getSituation());
                        surfaceRuptureFaultDisplacements.add(surfaceRuptureFaultDisplacement);
                    }
                    if(surfaceRuptureFaultList.size()>0){
                        surfaceRuptureRepository.batchSaveFault(surfaceRuptureFaultList);
                    }
                    if(surfaceRuptureFaultDisplacements.size()>0){
                        surfaceRuptureRepository.batchSaveFaultDisplacement(surfaceRuptureFaultDisplacements);
                    }
                }
            }
        }else{
            throw new RuntimeException("评估未完成,获取不到25公里范围内的活断层数据无地表破裂带评估结果");
        }
        String msg = hasEvaluateResult(drsId);
        if(StringUtils.isNotBlank(msg)){
            throw new RuntimeException("无评估结果");
        }

        //更新地表破裂带长度和同震位移
        surfaceRuptureRepository.updateRuptureLengthAndDisplacement(drsId,ruptureLength,displacement);

        //发震构造评估
        seismogenicStructureSstimate(longitude,latitude,sameNameFaultList,evaluateFault,maxParentNum);
        //评估结果
        return getSurfaceRuptureById(drsId);
    }
    /**
     * 应用于定时评估地表破裂带
     */
    @Override
    public void createEvaluateResult(SurfaceRuptureVO vo, BigDecimal longitude, BigDecimal latitude) throws Exception {
        String userId = PlatformSessionContext.getUserID();
        String userJson = sUserService.getSUser(userId);
        SUser sUser = CreateGson.createGson().fromJson(userJson, SUser.class);
        String msg = this.queryProvinceCityCountyNameStringByLonLat(longitude.toString(), latitude.toString());
        String province = "";
        String city = "";
        String county = "";
        if(StringUtils.isNotBlank(msg)){
            String[] split = msg.split(",");
            province = split[0];
            if(split.length==2){
                city = split[1];
            }else if(split.length==3){
                city = split[1];
                county = split[2];
            }
        }
        if(StringUtils.isBlank(province)){
            throw new RuntimeException("根据经纬度无法查询到地域信息");
        }
        String idByCondition = sysAreaService.getIdByCondition(URLEncoder.encode(province,"UTF-8"), URLEncoder.encode(city,"UTF-8"),URLEncoder.encode(county,"UTF-8") );
        String provinceId = "";
        String cityId = "";
        String countyId = "";
        if(StringUtils.isNotBlank(idByCondition)){
            String[] split = idByCondition.split("_");
            if(split.length==1){
                provinceId = split[0];
            }else if(split.length==2){
                provinceId = split[0];
                cityId = split[1];
            }else{
                provinceId = split[0];
                cityId = split[1];
                countyId = split[2];
            }
        }
        //保存最终符合条件的断层数据
        List<Fault> resultFaultList = new ArrayList<>();
        //根据省份判断所属分区
        String subregion = getSubregionByProvince(province);
        String partition = getPartitionByProvince(province);
        //页面选择的断层性质 只做保存不参与计算
        Integer faultProperties = vo.getFaultProperties();
        //查询字典获取数据
        Map<String, String> featureMap = getFeatureMap();
        if(featureMap==null || featureMap.values().size()==0){
            throw new RuntimeException("评估失败,请至字典项中维护断层性质");
        }
        //计算地表破裂宽度
        BigDecimal ruptureWidth = getRuptureWidth(partition,vo.getEarthQuakeLevel());
        //计算地表破裂长度
        BigDecimal ruptureLength = BigDecimal.ZERO;
        //计算同震位移
        BigDecimal displacement = BigDecimal.ZERO;
        //保存相同断层版本下所有断层名称相同的断层
        List<Fault> sameNameFaultList = new ArrayList<>();
        //
        Fault evaluateFault  = null;
        //根据经纬度获取25公里范围内的活断层数据
        List<Fault> kilometerFaultData = get25KilometerFaultData(longitude, latitude, vo.getFaultVersion());
        List<Fault> tempFaultList = new ArrayList<Fault>();
        //地表破裂带编号
        String maxParentNum = "";
        if(PlatformObjectUtils.isNotEmpty(kilometerFaultData) && kilometerFaultData.size()>1){
            //筛选最新时代为Qh、Qh3、Qh2、Qp3、Qp32、Qp31的断层数据
            List<Fault> faultList = kilometerFaultData.stream().filter(fault -> {
                return getLatestActivePeriod().contains(fault.getLatestActivePeriod());
            }).collect(Collectors.toList());
            if(PlatformObjectUtils.isEmpty(faultList) || faultList.size()==0){
                throw new RuntimeException("评估未完成,获取不到最新时代为Qh、Qh3、Qh2、Qp3、Qp32、Qp31的断层数据无地表破裂带评估结果");
            }
            int size = faultList.size();
            if(size>1){
                //表示存在多条符合条件的断层数据
                faultList.forEach(fault -> {
                    //获取投影距离在3Km内的所有的断层数据
                    List<Fault> km3Fault = get3kmFault(fault, longitude, latitude, vo.getSourceDepth());
                    if((PlatformObjectUtils.isNotEmpty(km3Fault)&& km3Fault.size()>0)){
                        tempFaultList.addAll(km3Fault);
                    }
                });
                if(PlatformObjectUtils.isEmpty(tempFaultList) || tempFaultList.size()==0){
                    throw new RuntimeException("评估未完成,获取不到投影距离在3Km内的断层数据无地表破裂带评估结果");
                }
                //长度区间
                String lengthSection = "";
                //两者投影点距离在3km以内的断层数据还是有多条
                if(tempFaultList.size()>1){
                      // 遍历断层，分别到基础数据的jc_instrument_catalog（1970年以来小震目录）和jc_stratum_lithology（历史4
                      // 3/4以上强震目录）中获取到断层距离为3公里的小镇，判断断层附近的小镇数量哪个多就取哪个断层
                      // MULTILINESTRING((101.96971250482832 29.96109458854447,101.96900014733897
                      // 29.962479064257476,101.96861375002456 29.96376074296402,101.9686131151033
                      // 29.963763977825376,101.96829869502878 29.965366000440653))
                    Fault fault = getMostTownFault(tempFaultList);
                    evaluateFault = fault;
                    //获取相同名称的断层且断层长度之和在地表劈裂带区间范围的断层
                    sameNameFaultList.add(fault);
                    //断层性质
                    String featureName = featureMap.get(fault.getFeature() + "");
                    //计算同震位移
                    displacement = getDisplacement(featureName,subregion,vo.getEarthQuakeLevel());
                    //计算地表破裂长度
                    ruptureLength = getRuptureLength(featureName,subregion,vo.getEarthQuakeLevel());
                    //计算地表破裂长度区间
                    lengthSection = getCalculateLengthSection(ruptureLength,vo.getEarthQuakeLevel());
                    //活断层可能是分段的，要获取其他的相同名称的断层
                    List<Fault> hashFaultList = listByNameExcludeId(fault.getDcName(),fault.getId(),vo.getFaultVersion());
                    if(PlatformObjectUtils.isNotEmpty(hashFaultList) && hashFaultList.size()>0){
                        sameNameFaultList.addAll(hashFaultList);
                    }
                    Map<Integer,Fault> resultFault = getData(fault,vo.getEarthQuakeLevel(),lengthSection,hashFaultList);
                    //最终的地表破裂带长度 是断层长度之和在上面区间范围内的所有断层的长度之和
                    //ruptureLength = BigDecimal.ZERO;
                    if(PlatformObjectUtils.isNotEmpty(resultFault)){
                        Iterator<Fault> iterator = resultFault.values().iterator();
                        while (iterator.hasNext()){
                            Fault next = iterator.next();
                            ruptureLength = ruptureLength.add(new BigDecimal(next.getJfLength()));
                            Fault tempFault = next;
                            //断层方向
                            tempFault.setSituation(getFaultSituation(featureName));
                            resultFaultList.add(tempFault);
                        }
                    }
                }else if(tempFaultList.size()==1){
                    Fault fault = tempFaultList.get(0);
                    evaluateFault = fault;
                    sameNameFaultList.add(fault);
                    //断层性质
                    String featureName = featureMap.get(fault.getFeature() + "");
                    //计算同震位移
                    displacement = getDisplacement(featureName,subregion,vo.getEarthQuakeLevel());
                    //计算地表破裂长度
                    ruptureLength = getRuptureLength(featureName,subregion,vo.getEarthQuakeLevel());
                    //计算地表破裂长度区间
                    lengthSection = getCalculateLengthSection(ruptureLength,vo.getEarthQuakeLevel());
                    //获取相同名称的断层且断层长度之和在地表劈裂带区间范围的断层
                    //活断层可能是分段的，要获取其他的相同名称的断层
                    List<Fault> hashFaultList = listByNameExcludeId(fault.getDcName(),fault.getId(),vo.getFaultVersion());
                    if(PlatformObjectUtils.isNotEmpty(hashFaultList) && hashFaultList.size()>0){
                        sameNameFaultList.addAll(hashFaultList);
                    }
                    Map<Integer,Fault> resultFault = getData(fault,vo.getEarthQuakeLevel(),lengthSection,hashFaultList);
                    //最终的地表破裂带长度 是断层长度之和在上面区间范围内的
                    //ruptureLength = BigDecimal.ZERO;
                    if(PlatformObjectUtils.isNotEmpty(resultFault)){
                        Iterator<Fault> iterator = resultFault.values().iterator();
                        while (iterator.hasNext()){
                            Fault next = iterator.next();
                            ruptureLength = ruptureLength.add(new BigDecimal(next.getJfLength()));
                            Fault tempFault = next;
                            //断层方向
                            tempFault.setSituation(getFaultSituation(featureName));
                            resultFaultList.add(tempFault);
                        }
                    }
                }
                //保存地表破裂带的基本信息
                SurfaceRupture surfaceRupture = new SurfaceRupture();
                synchronized (this){
                    maxParentNum = getTaskCode(surfaceRuptureRepository.getMaxNum());
                    surfaceRupture.setDsrId(UUIDGenerator.getUUID()).setEvaluateUser(userId).setEvaluateUserName(sUser.getUserName()).setNum(maxParentNum).setSourceDepth(vo.getSourceDepth()).setGeom("POINT("+longitude+" "+latitude+")")
                            .setEvaluateTime(new Date()).setDataSource("1").setLongitude(longitude).setLatitude(latitude).setRuptureLength(ruptureLength).setFaultProperties(faultProperties+"")
                            .setDisplacement(displacement).setRuptureWidth(ruptureWidth).setLengthSection(lengthSection).setProvince(province).setFaultVersion(vo.getFaultVersion()).setEarthQuakeLevel(vo.getEarthQuakeLevel())
                            .setCity(city).setCounty(county).setProvinceId(provinceId).setCityId(cityId).setCountyId(countyId).setDelFlag(YNEnum.N.toString()).setEarthQuakeTime(new Date()).setSourceFrom("1");
                    surfaceRuptureRepository.evaluate(Arrays.asList(surfaceRupture));
                }
                //保存地表破裂带区间范围内的断层
                if(resultFaultList.size()>0){
                    List<SurfaceRuptureFaultDisplacement> surfaceRuptureFaultDisplacements =  new ArrayList<>();
                    List<SurfaceRuptureFault> surfaceRuptureFaultList = new ArrayList<>();
                    for (Fault fault : resultFaultList) {
                        String id = UUIDGenerator.getUUID();
                        SurfaceRuptureFault surfaceRuptureFault = new SurfaceRuptureFault();
                        BeanUtils.copyProperties(fault,surfaceRuptureFault);
                        surfaceRuptureFault.setPreFault(PlatformObjectUtils.isNotEmpty(fault.getPreFault())?fault.getPreFault().getId():"");
                        surfaceRuptureFault.setPostFault(PlatformObjectUtils.isNotEmpty(fault.getPostFault())?fault.getPostFault().getId():"");
                        surfaceRuptureFault.setNum(maxParentNum);
                        surfaceRuptureFault.setCreateTime(new Date());
                        surfaceRuptureFault.setCreateUserId(PlatformObjectUtils.isNotEmpty(PlatformSessionContext.getUserID())?PlatformSessionContext.getUserID():"80cd530287e54c6788925adf2dfc9da1");
                        surfaceRuptureFault.setNum(maxParentNum);
                        surfaceRuptureFault.setFaultId(fault.getId());
                        surfaceRuptureFault.setId(id);
                        surfaceRuptureFaultList.add(surfaceRuptureFault);
                        SurfaceRuptureFaultDisplacement surfaceRuptureFaultDisplacement = new SurfaceRuptureFaultDisplacement();
                        surfaceRuptureFaultDisplacement.setId(fault.getId());
                        surfaceRuptureFaultDisplacement.setNum(maxParentNum);
                        surfaceRuptureFaultDisplacement.setCenterGeom(fault.getCenterGeom());
                        surfaceRuptureFaultDisplacement.setSituation(fault.getSituation());
                        surfaceRuptureFaultDisplacement.setId(id);
                        surfaceRuptureFaultDisplacement.setFaultId(fault.getId());
                        surfaceRuptureFaultDisplacements.add(surfaceRuptureFaultDisplacement);
                    }
                    if(surfaceRuptureFaultList.size()>0){
                        surfaceRuptureRepository.batchSaveFault(surfaceRuptureFaultList);
                    }
                    if(surfaceRuptureFaultDisplacements.size()>0){
                        surfaceRuptureRepository.batchSaveFaultDisplacement(surfaceRuptureFaultDisplacements);
                    }
                }
            }else{
                //只有一条符合条件的断层数据
                Fault fault = faultList.get(0);
                resultFaultList.add(fault);
                evaluateFault = fault;
                sameNameFaultList.add(fault);
                //断层性质
                String featureName = featureMap.get(fault.getFeature() + "");
                //计算同震位移
                displacement = getDisplacement(featureName,subregion,vo.getEarthQuakeLevel());
                //计算地表破裂长度
                ruptureLength = getRuptureLength(featureName,subregion,vo.getEarthQuakeLevel());
                //计算地表破裂长度区间
                String lengthSection = getCalculateLengthSection(ruptureLength,vo.getEarthQuakeLevel());
                //活断层可能是分段的，要获取其他的相同名称的断层
                List<Fault> hashFaultList = listByNameExcludeId(fault.getDcName(),fault.getId(),vo.getFaultVersion());
                if(PlatformObjectUtils.isNotEmpty(hashFaultList) && hashFaultList.size()>0){
                    sameNameFaultList.addAll(hashFaultList);
                }
                Map<Integer,Fault> resultFault = getData(fault,vo.getEarthQuakeLevel(),lengthSection,hashFaultList);
                //最终的地表破裂带长度 是断层长度之和在上面区间范围内的
                //ruptureLength = BigDecimal.ZERO;
                if(PlatformObjectUtils.isNotEmpty(resultFault)){
                    Iterator<Fault> iterator = resultFault.values().iterator();
                    while (iterator.hasNext()){
                        Fault next = iterator.next();
                        ruptureLength = ruptureLength.add(new BigDecimal(next.getJfLength()));
                        Fault tempFault = next;
                        //断层方向
                        tempFault.setSituation(getFaultSituation(featureName));
                        resultFaultList.add(tempFault);
                    }
                }
                //保存地表破裂带的基本信息
                SurfaceRupture surfaceRupture = new SurfaceRupture();
                synchronized (this){
                    maxParentNum = getTaskCode(surfaceRuptureRepository.getMaxNum());
                    surfaceRupture.setDsrId(UUIDGenerator.getUUID()).setEvaluateUser(userId).setEvaluateUserName(sUser.getUserName()).setNum(maxParentNum).setSourceDepth(vo.getSourceDepth()).setGeom("POINT("+longitude+" "+latitude+")")
                            .setEvaluateTime(new Date()).setDataSource("1").setLongitude(longitude).setLatitude(latitude).setRuptureLength(ruptureLength).setFaultProperties(faultProperties+"")
                            .setDisplacement(displacement).setRuptureWidth(ruptureWidth).setLengthSection("").setProvince(province).setFaultVersion(vo.getFaultVersion()).setEarthQuakeLevel(vo.getEarthQuakeLevel())
                            .setCity(city).setCounty(county).setProvinceId(provinceId).setCityId(cityId).setCountyId(countyId).setDelFlag(YNEnum.N.toString()).setEarthQuakeTime(new Date()).setSourceFrom("1");
                    surfaceRuptureRepository.evaluate(Arrays.asList(surfaceRupture));
                }
                //保存地表破裂带区间范围内的断层
                if(resultFaultList.size()>0){
                    List<SurfaceRuptureFaultDisplacement> surfaceRuptureFaultDisplacements =  new ArrayList<>();
                    List<SurfaceRuptureFault> surfaceRuptureFaultList = new ArrayList<>();
                    for (Fault f : resultFaultList) {
                        String id = UUIDGenerator.getUUID();
                        SurfaceRuptureFault surfaceRuptureFault = new SurfaceRuptureFault();
                        BeanUtils.copyProperties(f,surfaceRuptureFault);
                        surfaceRuptureFault.setPreFault(PlatformObjectUtils.isNotEmpty(f.getPreFault())?f.getPreFault().getId():"");
                        surfaceRuptureFault.setPostFault(PlatformObjectUtils.isNotEmpty(f.getPostFault())?f.getPostFault().getId():"");
                        surfaceRuptureFault.setNum(maxParentNum);
                        surfaceRuptureFault.setCreateTime(new Date());
                        surfaceRuptureFault.setCreateUserId(PlatformObjectUtils.isNotEmpty(PlatformSessionContext.getUserID())?PlatformSessionContext.getUserID():"80cd530287e54c6788925adf2dfc9da1");
                        surfaceRuptureFault.setNum(maxParentNum);
                        surfaceRuptureFault.setFaultId(f.getId());
                        surfaceRuptureFault.setId(id);
                        surfaceRuptureFaultList.add(surfaceRuptureFault);
                        SurfaceRuptureFaultDisplacement surfaceRuptureFaultDisplacement = new SurfaceRuptureFaultDisplacement();
                        surfaceRuptureFaultDisplacement.setId(id);
                        surfaceRuptureFaultDisplacement.setFaultId(f.getId());
                        surfaceRuptureFaultDisplacement.setNum(maxParentNum);
                        surfaceRuptureFaultDisplacement.setCenterGeom(f.getCenterGeom());
                        surfaceRuptureFaultDisplacement.setSituation(f.getSituation());
                        surfaceRuptureFaultDisplacements.add(surfaceRuptureFaultDisplacement);
                    }
                    if(surfaceRuptureFaultList.size()>0){
                         surfaceRuptureRepository.batchSaveFault(surfaceRuptureFaultList);
                    }
                    if(surfaceRuptureFaultDisplacements.size()>0){
                        surfaceRuptureRepository.batchSaveFaultDisplacement(surfaceRuptureFaultDisplacements);
                    }
                }
            }
        }else{
            throw new RuntimeException("评估未完成,获取不到25公里范围内的活断层数据无地表破裂带评估结果");
        }
        //发震构造评估
        seismogenicStructureSstimate(longitude,latitude,sameNameFaultList,evaluateFault,maxParentNum);
    }

    //获取断层方向断层性质逆是垂直(1)方向，其他为水平(2)方向同震位移。
    private Integer getFaultSituation(String rupture){
       if("逆".equals(rupture)){
           return 1;
       }
       return 2;
    }
    //获取小镇数量最多的断层
    private Fault getMostTownFault(List<Fault> tempFaultList){
        Map<Fault,Integer> map = new HashMap<>();
        tempFaultList.forEach(entity -> {
            int sum = 0;
            String geom = entity.getGeom();
            //分别查询历史地震（历史4 3/4以上强震目录、1970年以来小震目录），获取与该断层范围3公里内的城镇数量
            sum+=getStrongCatalog(geom);
            sum+=getInstrumentCatalog(geom);
            map.put(entity,sum);
        });

        List<Map.Entry<Fault,Integer>> tempList = new ArrayList(map.entrySet());
        Collections.sort(tempList, (o1, o2) -> (o1.getValue() - o2.getValue()));
        //小镇数量多的断层数据
        return (Fault) tempList.get(tempList.size()-1).getKey();
    }
    //获取3km范围内的断层数据
    private List<Fault> get3kmFault(Fault fault,BigDecimal longitude,BigDecimal latitude,BigDecimal sourceDepth){
        String geomText = "POINT("+ longitude+" "+latitude+")";
        List<Fault> tempFaultList = new ArrayList<>();
        //获取断层到震中位置最近的点POINT(119.54634736208214 37.11882760134029)
        String pointGeomText = surfaceRuptureRepository.getShortestPoint(fault.getGeom(),geomText);
        int prefix = pointGeomText.indexOf("(");
        int subfix = pointGeomText.indexOf(")");
        //119.54634736208214 37.11882760134029
        String position = pointGeomText.substring(prefix+1,subfix);
        //计算改点到震中位置的水平距离（米）
        String longitudeLatitude =  "LINESTRING("+position+","+longitude+" "+latitude+")";
        BigDecimal distince = surfaceRuptureRepository.getShortestDistince(longitudeLatitude);
        //换算成米
        sourceDepth = sourceDepth.multiply(BigDecimal.valueOf(1000));
        //断层角度
        Double clination = fault.getClination();
        if(clination!=null){
            //投影距离
            BigDecimal sinAngle = new BigDecimal(Math.sin(clination));
            BigDecimal cosAngle = new BigDecimal(Math.sin(clination));
            //继续判断两者投影点距离在3km以内
            BigDecimal projectionDistance = distince.multiply(sinAngle).subtract(sourceDepth.multiply(cosAngle));
            if(projectionDistance.compareTo(BigDecimal.valueOf(3000))<0){
                tempFaultList.add(fault);
            }
        }
        return  tempFaultList;
    }
    private Map<String, String> getFeatureMap(){
        //查询字典获取数据
        List<DictEntityVo> featureList = dictItemRepository.getDictItemByDictDirId("surfaceRupture");
        return  buildFeatureMap(featureList);
    }

    private  Map<Integer,Fault>  getData(Fault fault,BigDecimal earthQuakeLevel,String lengthSection,List<Fault> hashFaultList){
        AtomicInteger atomicInteger = new AtomicInteger(1);
        Map<Integer,Fault> faultBiMap = new HashMap<>();
        //获取同震位移中点
        fault.setCenterGeom(getCenterGeomText(fault.getGeom()));
        //断层的长度
        BigDecimal faultLength = new BigDecimal(fault.getJfLength());
        //切换标识，用于获取空间数据的最后一个或第一个经纬度
        String first = "first";
        String end = "end";

        Fault currentFault = fault;
        //最近距离的断层
        Fault shortestFault = null;
        //切换标识
        int cut = 0;
        //去除前后缀括号
        String tempGeomText = removePrefixSubfix(currentFault.getGeom());

        BigDecimal maxSection = new BigDecimal(lengthSection.split("_")[1]);
        BigDecimal minSection = new BigDecimal(lengthSection.split("_")[0]);
        //一个或n个相邻断层的长度应该在地表破裂带长度区间内
        // 当断层分段时，根据是否终止破裂及破裂长度是否在L最小|区间值-L|区间内，判断是否要此段段层，如果在区间范围内，则包含整段断层。否则将超出部分的断层整个舍弃。
        //最终L的值就是在这个区间范围内的所有的断层的长度和
        boolean start = true;
        Integer one = -1;
        int i = 0;
        while(faultLength.compareTo(maxSection)<=0 && faultLength.compareTo(minSection)>=0){
            if(shortestFault!=null){
                //获取同震位移中点
                shortestFault.setCenterGeom(getCenterGeom(shortestFault.getGeom()));
                //构建断层链表，当前断层关联前一个断层和后一个断层
                buildLinkedFault(first,currentFault,shortestFault);
                if(PlatformObjectUtils.isNotEmpty(currentFault.getPreFault()) && PlatformObjectUtils.isNotEmpty(currentFault.getPostFault())){
                    faultBiMap.put(atomicInteger.get(),currentFault);
                    Fault tempFault  = null;
                    if(cut==0){
                        if(start){
                            tempFault = currentFault;
                            start = false;
                        }else{
                            tempFault = faultBiMap.get(atomicInteger.get()+one);
                        }
                        currentFault = tempFault.getPreFault();
                        currentFault.setPostFault(tempFault);
                        cut = 1;
                    }else{
                        tempFault =  faultBiMap.get(atomicInteger.get()+one);
                        currentFault = tempFault.getPostFault();
                        currentFault.setPreFault(tempFault);
                        cut = 0;
                    }
                    tempGeomText = removePrefixSubfix(currentFault.getGeom());
                    atomicInteger.set(atomicInteger.addAndGet(1));
//                    //表示当前断层有前后断层结点
//                    if(cut==0){
//                        Fault temp = currentFault;
//                        currentFault = currentFault.getPreFault();
//                        currentFault.setPostFault(temp);
//                        cut = 1;
//                    }else{
//                        //循环向后查找第一个没有后结点的断层
//                        Fault temp = currentFault;
//                        currentFault = currentFault.getPreFault();
//                        currentFault.setPreFault(temp);
//                        cut = 0;
//                    }
                    tempGeomText = removePrefixSubfix(currentFault.getGeom());
                }
                shortestFault = null;
            }
            if(currentFault.getPreFault()==null){
                first = "first";
                end = "end";
            }else if(currentFault.getPostFault()==null){
                first = "end";
                end = "first";
            }
            if(PlatformObjectUtils.isNotEmpty(hashFaultList) && hashFaultList.size()>0){
                //获得第一个或最后一个经纬度
                String positionLonLat = getPositionLonLat(first, tempGeomText);
                BigDecimal lon = new BigDecimal(positionLonLat.split(" ")[0]);
                BigDecimal lat = new BigDecimal(positionLonLat.split(" ")[1]);
                // 表示该断层被分段
                BigDecimal distince = null;
                for (Fault hashFault : hashFaultList) {
                    String geomText = removePrefixSubfix(getGeomText(hashFault.getGeom()));
                    //获取相邻断层数据
                    String currentPositionLonLat = getPositionLonLat(end, geomText);
                    BigDecimal currentLon = new BigDecimal(currentPositionLonLat.split(" ")[0]);
                    BigDecimal currentLat = new BigDecimal(currentPositionLonLat.split(" ")[1]);
                    BigDecimal shortestDistince = getAdjoinFault(lon,lat,currentLon,currentLat);
                    if(distince==null || distince.compareTo(shortestDistince)>0){
                        distince = shortestDistince;
                        shortestFault = hashFault;
                    }
                }
                //前一个或后一个相邻的断层
                if(shortestFault!=null){
                    //判断相邻断层之间的距离是否在地表破裂终止距离内，如果在则会记录，如果不在则舍弃
                    if(endPositionOfSurfaceRupture(earthQuakeLevel).compareTo(distince)>=0){
                        faultLength = new BigDecimal(shortestFault.getJfLength()).add(faultLength);
                        distince = null;
                    }else{
                        break;
                    }
                }
            }else{
                //如果没有获取到相同名称的断层，表示该断层未被分段则直接跳出
                break;
            }
        }
        return faultBiMap;
    }

    //获取地表破裂带长度区间范围内的断层信息
    private  Fault  getData1(Fault fault,BigDecimal earthQuakeLevel,String lengthSection,List<Fault> hashFaultList){
        List<Fault> faultList = new ArrayList<>();
        //获取同震位移中点
        fault.setCenterGeom(getCenterGeomText(fault.getGeom()));
        //断层的长度
        BigDecimal faultLength = new BigDecimal(fault.getJfLength());
        //切换标识，用于获取空间数据的最后一个或第一个经纬度
        String first = "first";
        String end = "end";

        Fault currentFault = fault;
        //最近距离的断层
        Fault shortestFault = null;
        //切换标识
        int cut = 0;
        //去除前后缀括号
        String tempGeomText = removePrefixSubfix(currentFault.getGeom());

        BigDecimal maxSection = new BigDecimal(lengthSection.split("_")[1]);
        BigDecimal minSection = new BigDecimal(lengthSection.split("_")[0]);
        //一个或n个相邻断层的长度应该在地表破裂带长度区间内
        // 当断层分段时，根据是否终止破裂及破裂长度是否在L最小|区间值-L|区间内，判断是否要此段段层，如果在区间范围内，则包含整段断层。否则将超出部分的断层整个舍弃。
        //最终L的值就是在这个区间范围内的所有的断层的长度和
        while(faultLength.compareTo(maxSection)<=0 && faultLength.compareTo(minSection)>=0){
            if(shortestFault!=null){
                //获取同震位移中点
                shortestFault.setCenterGeom(getCenterGeom(shortestFault.getGeom()));
                //构建断层链表，当前断层关联前一个断层和后一个断层
                buildLinkedFault(first,currentFault,shortestFault);
                if(PlatformObjectUtils.isNotEmpty(currentFault.getPreFault()) && PlatformObjectUtils.isNotEmpty(currentFault.getPostFault())){
                    //表示当前断层有前后断层结点
                    Fault temp = null;
                    if(cut==0){
                        //循环向前查找第一个没有前结点的断层
                        while(currentFault.getPreFault()!=null){
                            temp = currentFault;
                            currentFault = currentFault.getPreFault();
                        }
                        currentFault.setPostFault(temp);
                        cut = 1;
                    }else{
                        //循环向后查找第一个没有后结点的断层
                        while(currentFault.getPostFault()!=null){
                            temp = currentFault;
                            currentFault = currentFault.getPostFault();
                        }
                        currentFault.setPreFault(temp);
                        cut = 0;
                    }
                    tempGeomText = removePrefixSubfix(currentFault.getGeom());
                }
                shortestFault = null;
            }
            if(currentFault.getPreFault()==null){
                first = "first";
                end = "end";
            }else if(currentFault.getPostFault()==null){
                first = "end";
                end = "first";
            }
            if(PlatformObjectUtils.isNotEmpty(hashFaultList) && hashFaultList.size()>0){
                //获得第一个或最后一个经纬度
                String positionLonLat = getPositionLonLat(first, tempGeomText);
                BigDecimal lon = new BigDecimal(positionLonLat.split(" ")[0]);
                BigDecimal lat = new BigDecimal(positionLonLat.split(" ")[1]);
                // 表示该断层被分段
                BigDecimal distince = null;
                for (Fault hashFault : hashFaultList) {
                    String geomText = removePrefixSubfix(getGeomText(hashFault.getGeom()));
                    //获取相邻断层数据
                    String currentPositionLonLat = getPositionLonLat(end, geomText);
                    BigDecimal currentLon = new BigDecimal(currentPositionLonLat.split(" ")[0]);
                    BigDecimal currentLat = new BigDecimal(currentPositionLonLat.split(" ")[1]);
                    BigDecimal shortestDistince = getAdjoinFault(lon,lat,currentLon,currentLat);
                    if(distince==null || distince.compareTo(shortestDistince)>0){
                        distince = shortestDistince;
                        shortestFault = hashFault;
                    }
                }
                //前一个或后一个相邻的断层
                if(shortestFault!=null){
                    //判断相邻断层之间的距离是否在地表破裂终止距离内，如果在则会记录，如果不在则舍弃
                    if(endPositionOfSurfaceRupture(earthQuakeLevel).compareTo(distince)>=0){
                        faultLength = new BigDecimal(shortestFault.getJfLength()).add(faultLength);
                        distince = null;
                    }else{
                        break;
                    }
                }
            }else{
                //如果没有获取到相同名称的断层，表示该断层未被分段则直接跳出
                break;
            }
        }
        return currentFault;
    }

    private String getGeomText(String geom) {
        return surfaceRuptureRepository.getGeomText(geom);
    }

    private String getCenterGeomText(String geomText) {
        return surfaceRuptureRepository.getCenterGeomText(geomText);
    }
    private String getCenterGeom(String geom) {
        return surfaceRuptureRepository.getCenterGeom(geom);
    }

    private void buildLinkedFault(String first,Fault currentFault,Fault shortestFault){
        if("end".equals(first)){
            currentFault.setPostFault(shortestFault);
        }
        if("first".equals(first)){
            currentFault.setPreFault(shortestFault);
        }
    }

    //获取相邻断层(根据两个断层的第一个经纬度和另一个断层的经纬度计算：先获取直角点（直角点的经纬度分别和两个断层的经度和纬度相同），构建出了直角三角形
    // 分别直角边的长度，最后求斜边的长度)
    private BigDecimal getAdjoinFault(BigDecimal lon, BigDecimal lat, BigDecimal currentLon, BigDecimal currentLat) {
        //经度差
        BigDecimal oneLength = surfaceRuptureRepository.getFaultLength(lon,lat,currentLon,lat);
        //纬度差
        BigDecimal twoLength = surfaceRuptureRepository.getFaultLength(currentLon,currentLat,currentLon,lat);
        double sqrt = Math.sqrt(Math.pow(oneLength.doubleValue(), 2) + Math.pow(twoLength.doubleValue(), 2));
        return BigDecimal.valueOf(sqrt);
    }

    //构建断层性质编码与断层性质的对应关系
    private Map<String,String> buildFeatureMap(List<DictEntityVo> featureList){
        return featureList.stream().collect(Collectors.toMap(DictEntityVo::getDictItemId,DictEntityVo::getDictName));
    }
    private String getPositionLonLat(String position,String geom){
        String[] split = geom.split(",");
        //获取首位经纬度
        if("first".equals(position)){
            return split[0];
        }
        //获取尾部经纬度
        return split[split.length-1];
    }
    //去除空间数据的前后缀和括号
    private String removePrefixSubfix(String geom) {
        geom = geom.replace("MULTILINESTRING((","");
        geom = geom.replace("))","");
        return geom;
    }

    private List<Integer> getLatestActivePeriod(){
        Integer[] array = new Integer[]{33320000,33320300,33320200,33310300,33310302,33310301};
        return Arrays.asList(array);
    }

    private int getStrongCatalog(String geom){
        String url = basicDataUrl + "/datacenter/jcStrongCatalog/dzzh/listByGeomRange";
        JSONObject valueMap = new JSONObject();
        valueMap.put("geom", geom);
        valueMap.put("range", "3000");
        JSONArray jsonArray = (JSONArray) drillService.getJCSJ(url, 4, valueMap).getData();
        return jsonArray.size();
    }

    private int getInstrumentCatalog(String geom){
        String url = basicDataUrl + "/datacenter/jcInstrumentCatalog/dzzh/listByGeomRange";
        JSONObject valueMap = new JSONObject();
        valueMap.put("geom", geom);
        valueMap.put("range", "3000");
        JSONArray jsonArray = (JSONArray) drillService.getJCSJ(url, 4, valueMap).getData();
        return jsonArray.size();
    }
    //发震构造评估
    @Override
    public void seismogenicStructureSstimate(BigDecimal longitude, BigDecimal latitude, List<Fault> sameNameFaultList,Fault evaluateFault,String num) throws Exception{
        /*//获取椭圆的长轴  为所有相同版本下相同名称断层的长度之和
        BigDecimal longAxis = BigDecimal.ZERO;
        for(Fault fault:sameNameFaultList){
            if(StringUtils.isNotBlank(fault.getJfLength())){
                longAxis = longAxis.add(new BigDecimal(fault.getJfLength()));
            }
        };
        //短轴长度 固定值
        BigDecimal shortAxis = longAxis.divide(BigDecimal.valueOf(5),2,RoundingMode.HALF_DOWN);
        //角度
        BigDecimal angle = BigDecimal.valueOf(evaluateFault.getClination());*/
        //获取根据地表破裂带评估结果计算发震构造评估椭圆参数
        List<String> list = surfaceRuptureRepository.getEvaluateResultEllipseParams(num);
        longitude = new BigDecimal(list.get(0));
        latitude = new BigDecimal(list.get(1));
        BigDecimal longAxis = new BigDecimal(list.get(2));//长轴长度km
        BigDecimal shortAxis = new BigDecimal(list.get(3));//短轴长度km
        BigDecimal angle = new BigDecimal(list.get(4));//角度：与正北方向的夹角，[0,180]
        //生成椭圆的空间数据
        String geom  = createInfluenceEllipse(longitude.toString(),latitude.toString(),longAxis.toString(),shortAxis.toString(),angle.toString());
        //开始保存
        SeismogenicStructureStimate seismogenicStructureStimate = new SeismogenicStructureStimate();
        seismogenicStructureStimate.setDsssId(UUIDGenerator.getUUID());
        seismogenicStructureStimate.setLongitude(longitude);
        seismogenicStructureStimate.setLatitude(latitude);
        seismogenicStructureStimate.setLongAxis(longAxis);
        seismogenicStructureStimate.setShortAxis(shortAxis);
        seismogenicStructureStimate.setAngle(angle);
        seismogenicStructureStimate.setGeom(geom);
        seismogenicStructureStimate.setNum(num);
        surfaceRuptureRepository.saveSeismogenicStructureStimate(seismogenicStructureStimate);
    }

    //创建椭圆--根据经纬度、长轴（km）、短轴（km）、角度[0-180]（从正东方向逆时针计算长轴方向角度）
    public String createInfluenceEllipse(String lon, String lat, String long_x, String short_y, String angle) {
        String geom = "";
        try {
            if (!PlatformObjectUtils.isEmpty(lon) && !PlatformObjectUtils.isEmpty(lat)
                    && !PlatformObjectUtils.isEmpty(long_x) && !PlatformObjectUtils.isEmpty(short_y)) {
                double x = Double.parseDouble(lon);//经度
                double y = Double.parseDouble(lat);//纬度
                double macroaxis = Double.parseDouble(long_x) * 1000;//长轴（米）
                double brachyaxis = Double.parseDouble(short_y) * 1000;//短轴（米）
                double direction = 0;//旋转角度
                if (!PlatformObjectUtils.isEmpty(angle)) {
                    direction = Double.parseDouble(angle);//旋转角度
                }
                //创建椭圆
                Polygon ellipse = createEllipse(x, y, macroaxis, brachyaxis, direction);
                geom = ellipse.toString();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return geom;
    }



    /**
     * 定义地球半径（米）
     */
    //private final double R_EARTH = 6371000;
    private final double R_EARTH = 6378137;

    /**
     * 定义地球赤道周长（米）
     */
    private final double P_EARTH = 2 * Math.PI * R_EARTH;

    /**
     * 将Y轴的长度（米）转换成纬度
     *
     * @param length
     * @return
     */
    public double parseYLengthToDegree(double length) {
        //将length长度转换为度数
        double yDegree = length / P_EARTH * 360;
        return yDegree;
    }

    /**
     * 根据所在纬度，将X轴的长度（米）转换成经度
     * （因为不同纬度下，1°经度代表的长度不同）
     *
     * @param y      所在纬度
     * @param length 线段长度
     * @return
     */
    public double parseXLengthToDegree(double y, double length) {
        //将角度（纬度）转换为弧度
        double latRadian = Math.toRadians(y);
        //计算当前纬度地球周长
        double latPEarth = P_EARTH * Math.cos(latRadian);
        //将length长度转换为度数
        double xDegree = length / latPEarth * 360;
        return xDegree;
    }

    /**
     * 根据中心点经纬度、长轴、短轴、角度生成椭圆
     *
     * @param x
     * @param y
     * @param macroaxis
     * @param brachyaxis
     * @param direction
     * @return
     */
    public Polygon createEllipse(double x, double y, double macroaxis, double brachyaxis, double direction) {
        //将长短轴转换为度数
        double macroaxisDegree = parseXLengthToDegree(y, macroaxis);
        double brachyaxisDegree = parseYLengthToDegree(brachyaxis);
        //将夹角转换为弧度
        double radians = Math.toRadians(direction);
        //生成工厂类
        GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
        //设置中心点
        shapeFactory.setCentre(new Coordinate(x, y));
        //设置长轴长度
        shapeFactory.setWidth(macroaxisDegree);
        //设置短轴长度
        shapeFactory.setHeight(brachyaxisDegree);
        //设置长轴和X轴夹角
        shapeFactory.setRotation(radians);
        //生成椭圆对象
        Polygon ellipse = shapeFactory.createEllipse();
        return ellipse;
    }

    private List<Fault> get25KilometerFaultData(BigDecimal longitude, BigDecimal latitude, String faultVersion){
        String geomText = "POINT("+ longitude+" "+latitude+")";
        String bufferGeomText = lawAnalysisRepository.getBufferByGeomMeter(geomText,25 * 1000);
        String url = basicDataUrl + "/datacenter/sysDataVersion/queryAllByVersionCode";
        JSONObject valueMap = new JSONObject();
        valueMap.put("versionCode", faultVersion);
        valueMap.put("geom", bufferGeomText);
        if(PlatformObjectUtils.isNotEmpty(drillService.getJCSJ(url, 1, valueMap).getData())){
            JSONObject jsonObject = (JSONObject) drillService.getJCSJ(url, 1, valueMap).getData();
            JSONArray faultArray = jsonObject.getJSONArray("data");
            if (faultArray == null || faultArray.size() < 1) {
                throw new RuntimeException("该区域没有" + faultVersion + "版本的断层数据");
            }
            return JSONObject.parseArray(faultArray.toJSONString(),Fault.class);
        }
        return new ArrayList<>();
    }

    //获取除却自己的相同名称的断层数据
    private List<Fault> listByNameExcludeId(String faultName,String faultId,String faultVersion){
        String url = basicDataUrl + "/datacenter/jcFault/dzzh/listByNameExcludeId?name="+faultName+"&id="+faultId+"&dataVersion="+faultVersion;
        JSONObject valueMap = new JSONObject();
        if(PlatformObjectUtils.isNotEmpty(drillService.getJCSJ(url, 3, valueMap).getData())){
            JSONArray faultArray = (JSONArray) drillService.getJCSJ(url, 3, valueMap).getData();
            return JSONObject.parseArray(faultArray.toJSONString(),Fault.class);
        }
        return new ArrayList<>();
    }

    //保存断层信息
    private void saveFaultMsg(List<Fault> list,String maxParentNum){
        for (Fault fault : list) {
            //计算断层长度
            Double faultLength = surfaceRuptureRepository.getFaultLength(fault.getGeom());
            fault.setJfLength(String.valueOf(faultLength));
            fault.setNum(maxParentNum);
        }
        if(list.size()>0){
            surfaceRuptureRepository.batchSave(list);
        }
        //保存最长断层信息
        saveMaxLengthFault(list);
    }
    //保存最大长度的断层信息
    private void saveMaxLengthFault(List<Fault> list){
        int size = list.size();
        Fault fault = null;
        if(size==1){
            //表示该断层就是最长的断层
            fault = list.get(0);
        }else{
            //从众多断层中获取长度最长的一条数据
            fault = list.stream().max(Comparator.comparing(Fault::getJfLength)).get();
        }
        MaxLengthFault maxLengthFault = new MaxLengthFault();
        BeanUtils.copyProperties(fault,maxLengthFault);
        maxLengthFault.setDmlfId(UUIDGenerator.getUUID());
        surfaceRuptureRepository.saveMaxLengthFault(maxLengthFault);
    }


    @Override
    public Map<String, Object> page(PageQueryParam pageQueryParam) {
        return surfaceRuptureRepository.page(pageQueryParam);
    }


    /**
     * 生成编号
     */
    private  String getTaskCode(String maxParentNum) {
        StringBuilder stringBuilder=new StringBuilder("");
        String parentNum ="";
        LocalDate date = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String format = date.format(formatter);
        stringBuilder.append(format);
        DecimalFormat decimalFormat=new DecimalFormat("000");
        if(PlatformObjectUtils.isEmpty(maxParentNum)){
            int i = 1;
            parentNum=decimalFormat.format(i);
        }else{
            String substring = maxParentNum.substring(8);
            parentNum = decimalFormat.format(Integer.parseInt(substring) + 1);
        }
        stringBuilder.append(parentNum);
        return stringBuilder.toString();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<String> idList) {
        String userId = PlatformSessionContext.getUserID();
        String userJson = sUserService.getSUser(userId);
        SUser sUser = CreateGson.createGson().fromJson(userJson, SUser.class);
        Date updateTime = new Date();
        surfaceRuptureRepository.delete(idList,updateTime);
        //记录删除操作
        List<OperateLog> logs = new ArrayList<>();
        idList.forEach(id->{
            OperateLog log = new OperateLog();
            log.setDsrdlId(UUIDGenerator.getUUID()).setDsrId(id).setOperate("删除").setOperateTime(new Date()).setOperateUser(userId)
                    .setOperateUserName(sUser.getUserName());
            logs.add(log);
        });
        if(logs.size()>0){
            surfaceRuptureRepository.batchSaveLog(logs);
        }

    }

    /*  断裂阶区宽度
        M≥8.0级， 先存断裂阶区宽度大于5km停止破裂；
        8.0＞M≥7.5级，先存断裂阶区宽度大于5km停止破裂；
        7.5＞M≥7.0级，先存断裂阶区宽度大于3km停止破裂；
        7＞M≥6.5级，先存断裂阶区宽度大于2km停止破裂。
     */
    private BigDecimal endPositionOfSurfaceRupture(BigDecimal earthLevel){
        BigDecimal width = BigDecimal.ZERO;
        if(earthLevel.compareTo(BigDecimal.valueOf(8.0))>=0){
            width = BigDecimal.valueOf(5000);
        }else if(earthLevel.compareTo(BigDecimal.valueOf(8.0))<0 && earthLevel.compareTo(BigDecimal.valueOf(7.5))>=0){
            width = BigDecimal.valueOf(5000);
        }else if(earthLevel.compareTo(BigDecimal.valueOf(7.0))>=0 && earthLevel.compareTo(BigDecimal.valueOf(7.5))<0){
            width = BigDecimal.valueOf(3000);
        }else{
            width = BigDecimal.valueOf(2000);
        }
        return width;
    }
    /**
     * M≥8.0级， 破裂长度区间 200-430；
     * 8.0＞M≥7.5级，破裂长度区间 60-230；
     * 7.5＞M≥7.0级，破裂长度区间 15-160；
     * 7＞M≥6.5级，破裂长度区间 0-50。
     */
    private String getCalculateLengthSection(BigDecimal ruptureLength,BigDecimal earthQuakeLevel){
        String lengthSection = "";
        BigDecimal maxSection = BigDecimal.ZERO;
        BigDecimal minSection = BigDecimal.ZERO;
        if(earthQuakeLevel.compareTo(BigDecimal.valueOf(8.0))>=0){
            BigDecimal min = ruptureLength.subtract(BigDecimal.valueOf(200));
            BigDecimal max = BigDecimal.valueOf(430).subtract(ruptureLength);
            maxSection = ruptureLength.add(min.compareTo(max) >= 0 ? max : min);
            minSection = ruptureLength.subtract(min.compareTo(max) >= 0 ? max : min);
            //比430大取值430，否则取值maxSection
            maxSection = maxSection.compareTo(BigDecimal.valueOf(430)) > 0?BigDecimal.valueOf(430):maxSection;
            //比200小取值200，否则取值minSection
            minSection = minSection.compareTo(BigDecimal.valueOf(200)) < 0?BigDecimal.valueOf(200):minSection;
        }else if(earthQuakeLevel.compareTo(BigDecimal.valueOf(7.5))>=0 && earthQuakeLevel.compareTo(BigDecimal.valueOf(8.0))<0){
            BigDecimal min = ruptureLength.subtract(BigDecimal.valueOf(60));
            BigDecimal max = BigDecimal.valueOf(230).subtract(ruptureLength);
            maxSection = ruptureLength.add(min.compareTo(max) >= 0 ? max : min);
            minSection = ruptureLength.subtract(min.compareTo(max) >= 0 ? max : min);
            //比230大取值230，否则取值maxSection
            maxSection = maxSection.compareTo(BigDecimal.valueOf(230)) > 0?BigDecimal.valueOf(230):maxSection;
            //比60小取值60，否则取值minSection
            minSection = minSection.compareTo(BigDecimal.valueOf(60)) < 0?BigDecimal.valueOf(60):minSection;
        }else if(earthQuakeLevel.compareTo(BigDecimal.valueOf(7.5))<0 && earthQuakeLevel.compareTo(BigDecimal.valueOf(7.0))>=0){
            BigDecimal min = ruptureLength.subtract(BigDecimal.valueOf(15));
            BigDecimal max = BigDecimal.valueOf(160).subtract(ruptureLength);
            maxSection = ruptureLength.add(min.compareTo(max) >= 0 ? max : min);
            minSection = ruptureLength.subtract(min.compareTo(max) >= 0 ? max : min);
            //比160大取值160，否则取值maxSection
            maxSection = maxSection.compareTo(BigDecimal.valueOf(160)) > 0?BigDecimal.valueOf(160):maxSection;
            //比15小取值15，否则取值minSection
            minSection = minSection.compareTo(BigDecimal.valueOf(15)) < 0?BigDecimal.valueOf(15):minSection;
        }else if(earthQuakeLevel.compareTo(BigDecimal.valueOf(6.5))>=0 && earthQuakeLevel.compareTo(BigDecimal.valueOf(7.0))<0){
            BigDecimal min = ruptureLength.subtract(BigDecimal.ZERO);
            BigDecimal max = BigDecimal.valueOf(50).subtract(ruptureLength);
            maxSection = ruptureLength.add(min.compareTo(max) >= 0 ? max : min);
            minSection = ruptureLength.subtract(min.compareTo(max) >= 0 ? max : min);
            //比50大取值50，否则取值maxSection
            maxSection = maxSection.compareTo(BigDecimal.valueOf(50)) > 0?BigDecimal.valueOf(50):maxSection;
            //比0小取值150，否则取值minSection
            minSection = minSection.compareTo(BigDecimal.valueOf(0)) < 0?BigDecimal.valueOf(0):minSection;
        }
        lengthSection = (minSection+"_"+maxSection);
        return lengthSection;
    }
    private BigDecimal getRuptureWidth(String partition, BigDecimal earthQuakeLevel) {
        //公式 ：lg地表破裂宽度=c+d*earthQuakeLevel  c和d根据地区和断层性质分别取不同的值  不在组合（地区和断层性质）范围内的不做计算
        BigDecimal c = BigDecimal.ZERO;
        BigDecimal d = BigDecimal.ZERO;
        if("中国西部".equals(partition)){
            c = BigDecimal.valueOf(-3.4318);
            d = BigDecimal.valueOf(0.6434);
        }
        if("中国东部".equals(partition)){
            c = BigDecimal.valueOf(-1.7160);
            d = BigDecimal.valueOf(0.4326);
        }
        //计算地表破裂宽度
        if(c.compareTo(BigDecimal.ZERO) ==0 && d.compareTo(BigDecimal.ZERO)==0){
            return BigDecimal.ZERO;
        }
        BigDecimal center = d.multiply(earthQuakeLevel).add(c);
        return BigDecimal.valueOf(Math.pow(10, center.doubleValue()));
    }

    /**
     *
     * @param rupture
     * @param partition
     * @param earthQuakeLevel--左侧算法
     * @return
     */
    private BigDecimal getDisplacement(String rupture, String partition, BigDecimal earthQuakeLevel) {
        //公式 ：lg同震位移=c+d*earthQuakeLevel  c和d根据地区和断层性质分别取不同的值  不在组合（地区和断层性质）范围内的不做计算
        BigDecimal a = BigDecimal.ZERO;
        BigDecimal b = BigDecimal.ZERO;
        if("逆".equals(rupture)){
            a = BigDecimal.valueOf(7.00);
            b = BigDecimal.valueOf(1.05);
        }else {
            if ("新疆".equals(partition) && "走滑".equals(rupture)) {
                a = BigDecimal.valueOf(8.11);
                b = BigDecimal.valueOf(0.08);
            }
            if ("青藏".equals(partition) && "走滑".equals(rupture)) {
                a = BigDecimal.valueOf(7.13);
                b = BigDecimal.valueOf(0.68);
            }
            if ("青藏".equals(partition) && ("逆".equals(rupture))) {
                a = BigDecimal.valueOf(7.00);
                b = BigDecimal.valueOf(1.05);
            }
            if ("华北".equals(partition) && "正走滑".equals(rupture)) {
                a = BigDecimal.valueOf(7.65);
                b = BigDecimal.valueOf(0.69);
            }
        }
        //计算同震位移
        if(a.compareTo(BigDecimal.ZERO) ==0 && b.compareTo(BigDecimal.ZERO)==0){
            return BigDecimal.ZERO;
        }
        BigDecimal center = (earthQuakeLevel.subtract(a)).divide(b,2,RoundingMode.HALF_DOWN);
        return BigDecimal.valueOf(Math.pow(10, center.doubleValue()));
    }

    /**
     *
     * @param rupture
     * @param partition
     * @param earthQuakeLevel--右侧算法
     * @return
     */
    /*private BigDecimal getDisplacement(String rupture, String partition, BigDecimal earthQuakeLevel) {
        //公式 ：lg同震位移=c+d*earthQuakeLevel  c和d根据地区和断层性质分别取不同的值  不在组合（地区和断层性质）范围内的不做计算
        BigDecimal c = BigDecimal.ZERO;
        BigDecimal d = BigDecimal.ZERO;
        if("新疆".equals(partition) && "走滑".equals(rupture)){
            c = BigDecimal.valueOf(-0.28);
            d = BigDecimal.valueOf(0.11);
        }
        if("青藏".equals(partition) && "走滑".equals(rupture)){
            c = BigDecimal.valueOf(-3.37);
            d = BigDecimal.valueOf(0.53);
        }
        if("青藏".equals(partition) && ("逆".equals(rupture))){
            c = BigDecimal.valueOf(-6.34);
            d = BigDecimal.valueOf(0.91);
        }
        if("华北".equals(partition) && "正走滑".equals(rupture)){
            c = BigDecimal.valueOf(-7.86);
            d = BigDecimal.valueOf(1.04);
        }
        //计算同震位移
        if(c.compareTo(BigDecimal.ZERO) ==0 && d.compareTo(BigDecimal.ZERO)==0){
            return BigDecimal.ZERO;
        }
        BigDecimal center = d.multiply(earthQuakeLevel).add(c);
        return BigDecimal.valueOf(Math.pow(10, center.doubleValue()));
    }*/

    private BiMap<String,String> buildFaultProperties(){
        BiMap<String, String> faultPropertiesMap = HashBiMap.create();
        faultPropertiesMap.put("0", "走滑断层");
        faultPropertiesMap.put("1", "逆断层");
        faultPropertiesMap.put("2", "正断层");
        faultPropertiesMap.put("3", "正走滑");
        faultPropertiesMap.put("4", "逆走滑");
        return faultPropertiesMap;
    }
    /**
     * 计算地表破裂长度--左侧算法
     */
    private BigDecimal getRuptureLength(String rupture, String subregion,BigDecimal earthQuakeLevel) {
        //公式 ：lg地表破裂长度=c+d*earthQuakeLevel  c和d根据地区和断层性质分别取不同的值  不在组合（地区和断层性质）范围内的不做计算
        BigDecimal a = BigDecimal.ZERO;
        BigDecimal b = BigDecimal.ZERO;
        if("逆".equals(rupture)){
            a = BigDecimal.valueOf(4.21);
            b = BigDecimal.valueOf(1.85);
        }else {
            if ("新疆".equals(subregion) && "走滑".equals(rupture)) {
                a = BigDecimal.valueOf(6.48);
                b = BigDecimal.valueOf(0.80);
            }
            if ("青藏".equals(subregion) && "走滑".equals(rupture)) {
                a = BigDecimal.valueOf(5.92);
                b = BigDecimal.valueOf(0.88);
            }
            if ("青藏".equals(subregion) && ("逆".equals(rupture))) {
                a = BigDecimal.valueOf(4.21);
                b = BigDecimal.valueOf(1.85);
            }
            if ("华北".equals(subregion) && "正走滑".equals(rupture)) {
                a = BigDecimal.valueOf(6.84);
                b = BigDecimal.valueOf(0.65);
            }
        }
        //计算地表破裂长度L
        if(a.compareTo(BigDecimal.ZERO) ==0 && b.compareTo(BigDecimal.ZERO)==0){
            return BigDecimal.ZERO;
        }

        /*BigDecimal center = earthQuakeLevel.subtract(a).divide(b);
        return BigDecimal.valueOf(Math.pow(10, center.doubleValue()));*/
        BigDecimal center = (earthQuakeLevel.subtract(a)).divide(b,2,RoundingMode.HALF_DOWN);
        return BigDecimal.valueOf(Math.pow(10, center.doubleValue()));
    }

    /**
     * 计算地表破裂长度--右侧算法
     */
    /*private BigDecimal getRuptureLength(String rupture, String subregion,BigDecimal earthQuakeLevel) {
        //公式 ：lg地表破裂长度=c+d*earthQuakeLevel  c和d根据地区和断层性质分别取不同的值  不在组合（地区和断层性质）范围内的不做计算
        BigDecimal c = BigDecimal.ZERO;
        BigDecimal d = BigDecimal.ZERO;
        if("新疆".equals(subregion) && "走滑".equals(rupture)){
            c = BigDecimal.valueOf(-4.93);
            d = BigDecimal.valueOf(0.86);
        }
        if("青藏".equals(subregion) && "走滑".equals(rupture)){
            c = BigDecimal.valueOf(-1.39);
            d = BigDecimal.valueOf(0.43);
        }
        if("青藏".equals(subregion) && ("逆".equals(rupture))){
            c = BigDecimal.valueOf(-1.53);
            d = BigDecimal.valueOf(0.44);
        }
        if("华北".equals(subregion) && "正走滑".equals(rupture)){
            c = BigDecimal.valueOf(-3.42);
            d = BigDecimal.valueOf(0.64);
        }
        //计算地表破裂长度L
        if(c.compareTo(BigDecimal.ZERO) ==0 && d.compareTo(BigDecimal.ZERO)==0){
            return BigDecimal.ZERO;
        }
        BigDecimal center = d.multiply(earthQuakeLevel).add(c);
        return BigDecimal.valueOf(Math.pow(10, center.doubleValue()));
    }*/

    /** 根据省份判断所属分区 分区与省份关系： 新疆：新疆 青藏：西藏、青海、甘肃、四川、云南、宁夏 华北：其他省份都用华北 */
    private String getSubregionByProvince(String province) {
        if(province.contains("新疆")){
             return "新疆";
        }else if(province.contains("西藏") || province.contains("青海") || province.contains("甘肃")
                ||province.contains("四川")|| province.contains("云南") || province.contains("宁夏")){
            return "青藏";
        }
        return "华北";
    }

    /** 根据省份判断所属分区 分区与省份关系： 西部：西藏、青海、甘肃、四川、云南、宁夏、新疆 东部：其他地区都用东部 */
    private String getPartitionByProvince(String province) {
        if(province.contains("西藏") || province.contains("青海") || province.contains("甘肃") || province.contains("新疆")
                ||province.contains("四川")|| province.contains("云南") || province.contains("宁夏")){
            return "中国西部";
        }
        return "中国东部";
    }

    /**
     * 计算拼接经纬度
     */
    private Map<String, BigDecimal> getLongitudeAndLatitude(SurfaceRuptureVO vo) {
        Map<String, BigDecimal> map = new HashMap<>(2);
        //经度 -度
        BigDecimal longitudeH = vo.getLongitudeH();
        //经度 -分
        BigDecimal longitudeM = vo.getLongitudeM();
        //经度 -秒
        BigDecimal longitudeS = vo.getLongitudeS();
        //秒
        BigDecimal longitudeSecond = longitudeS.divide(BigDecimal.valueOf(60), 6, RoundingMode.HALF_DOWN);
        BigDecimal longitudeMinute = longitudeM.add(longitudeSecond);
        longitudeSecond = longitudeMinute.divide(BigDecimal.valueOf(60), 6, RoundingMode.HALF_DOWN);
        BigDecimal longitude = longitudeH.add(longitudeSecond);
        map.put("longitude",longitude);
        //经度 -度
        BigDecimal latitudeH = vo.getLatitudeH();
        //经度 -分
        BigDecimal latitudeM = vo.getLatitudeM();
        //经度 -秒
        BigDecimal latitudeS = vo.getLatitudeS();
        //秒
        BigDecimal latitudeSecond = latitudeS.divide(BigDecimal.valueOf(60), 6, RoundingMode.HALF_DOWN);
        BigDecimal latitudeMinute = latitudeM.add(latitudeSecond);
        latitudeSecond = latitudeMinute.divide(BigDecimal.valueOf(60), 6, RoundingMode.HALF_DOWN);
        BigDecimal latitude = latitudeH.add(latitudeSecond);
        map.put("latitude",latitude);
        return map;
    }

    /**
     * 根据经纬度获取省
     */
    @Override
    public String queryProvinceCityCountyNameStringByLonLat(String lon,String lat){
        String result = "";
        if (!PlatformObjectUtils.isEmpty(lon) && !PlatformObjectUtils.isEmpty(lat)) {
            //省
            BigDecimal longitude = new BigDecimal(lon);
            BigDecimal latitude = new BigDecimal(lat);
            if(longitude.compareTo(new BigDecimal(73.33))<0 || longitude.compareTo(new BigDecimal(135.05))>0){
                return "";
            }
            if(latitude.compareTo(new BigDecimal(3.51))<0 || latitude.compareTo(new BigDecimal(53.33))>0){
                return "";
            }
            List<String> provinceInfoList = queryProvinceByLonLat(lon,lat);
            if(provinceInfoList.size()>0){
                String provinceCode = provinceInfoList.get(0);
                String provinceName = provinceInfoList.get(1);
                result += provinceName;
                //市
                List<String> cityInfoList = queryCityByLonLat(lon,lat,provinceCode);
                if(cityInfoList.size()>0){
                    String cityCode = cityInfoList.get(0);
                    String cityName = cityInfoList.get(1);
                    result += "," + cityName;
                    //区县
                    List<String> countyInfoList = queryCountyByLonLat(lon,lat,cityCode);
                    if(countyInfoList.size()>0) {
                        String countyName = countyInfoList.get(1);
                        result += "," + countyName;
                    }
                }
            }
        }

        return result;
    }
    //根据经纬度查询行政区划--区县code和名称
    private List<String> queryCountyByLonLat(String lon,String lat,String cityCode){
        List<String> resultList = new ArrayList<String>();
        try {
            if (!PlatformObjectUtils.isEmpty(lon) && !PlatformObjectUtils.isEmpty(lat)) {
                //查询行政区划--区县
                String sql = "SELECT code,name FROM district_boundary_county t WHERE ";
                if (!PlatformObjectUtils.isEmpty(cityCode)) {//市code
                    String tempCode = cityCode.substring(0,4);
                    sql += "t.code like '"+tempCode+"%' and ";
                }
                sql += "ST_Within(ST_GeometryFromText('POINT ("+lon+" "+lat+")',4490),t.geom) ";

                Map<String, Object> map = jdbcTemplate.queryForMap(sql);
                if (map.values().size()>0) {
                    String code = (String)map.get("code");//行政区划编码
                    resultList.add(code);
                    String name = (String)map.get("name");//行政区划名称
                    resultList.add(name);
                }
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
        return resultList;
    }
    public List<String> queryProvinceByLonLat(String lon,String lat){
        List<String> resultList = new ArrayList<String>();
        try {
            if (!PlatformObjectUtils.isEmpty(lon) && !PlatformObjectUtils.isEmpty(lat)) {
                //查询行政区划--省
                String sql = "SELECT code,name FROM district_boundary_province t " +
                        "WHERE ST_Within(ST_GeometryFromText('POINT ("+lon+" "+lat+")',4490),t.geom) ";
                Map<String, Object> map = new HashMap<>();
                try {
                    map = jdbcTemplate.queryForMap(sql);
                    if (map.values().size() > 0) {
                        String code = (String) map.get("code");//行政区划编码
                        resultList.add(code);
                        String name = (String) map.get("name");//行政区划名称
                        resultList.add(name);
                    }
                }catch (Exception ex){
                   return new ArrayList<>();
                }
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }

        return resultList;
    }


    //根据经纬度查询行政区划--市code和名称
    private List<String> queryCityByLonLat(String lon,String lat,String provinceCode){
        List<String> resultList = new ArrayList<String>();
        try {
            if (!PlatformObjectUtils.isEmpty(lon) && !PlatformObjectUtils.isEmpty(lat)) {
                //查询行政区划--市
                String sql = "SELECT code,name FROM district_boundary_city t WHERE ";
                if (!PlatformObjectUtils.isEmpty(provinceCode)) {//省code
                    String tempCode = provinceCode.substring(0,2);
                    sql += "t.code like '"+tempCode+"%' and ";
                }
                sql += "ST_Within(ST_GeometryFromText('POINT ("+lon+" "+lat+")',4490),t.geom) ";

                Map<String, Object> map = jdbcTemplate.queryForMap(sql);
                if (map.values().size()>0) {
                    String code = (String)map.get("code");//行政区划编码
                    resultList.add(code);
                    String name = (String)map.get("name");//行政区划名称
                    resultList.add(name);
                }
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
        return resultList;
    }
    /**
     * 获取数据库连接
     * SQL语句
     */
    private Connection getConnection() throws Exception {
        Class.forName("org.postgresql.Driver");
        return DriverManager.getConnection(url, name, pwd);
    }

    @Override
    public String saveSurfaceRupture(SurfaceRuptureVO vo) throws UnsupportedEncodingException {
        String userId = PlatformObjectUtils.isNotEmpty(PlatformSessionContext.getUserID())?
                PlatformSessionContext.getUserID():"80cd530287e54c6788925adf2dfc9da1";
        String userJson = sUserService.getSUser(userId);
        SUser sUser = CreateGson.createGson().fromJson(userJson, SUser.class);
        //计算拼接经纬度
        Map<String, BigDecimal> map = getLongitudeAndLatitude(vo);
        BigDecimal longitude = map.get("longitude");
        BigDecimal latitude = map.get("latitude");
        String msg = this.queryProvinceCityCountyNameStringByLonLat(longitude.toString(), latitude.toString());
        String province = "";
        String city = "";
        String county = "";
        if(StringUtils.isNotBlank(msg)){
            String[] split = msg.split(",");
            province = split[0];
            if(split.length==2){
                city = split[1];
            }else if(split.length==3){
                city = split[1];
                county = split[2];
            }
        }
        if(StringUtils.isBlank(province)){
            throw new RuntimeException("根据经纬度无法查询到地域信息");
        }
        String idByCondition = sysAreaService.getIdByCondition(URLEncoder.encode(province,"UTF-8"), URLEncoder.encode(city,"UTF-8"),URLEncoder.encode(county,"UTF-8") );
        String provinceId = "";
        String cityId = "";
        String countyId = "";
        if(StringUtils.isNotBlank(idByCondition)){
            String[] split = idByCondition.split("_");
            if(split.length==1){
                provinceId = split[0];
            }else if(split.length==2){
                provinceId = split[0];
                cityId = split[1];
            }else{
                provinceId = split[0];
                cityId = split[1];
                countyId = split[2];
            }
        }

        //保存地表破裂带的基本信息
        SurfaceRupture surfaceRupture = new SurfaceRupture();
        String dsrId = UUIDGenerator.getUUID();
        synchronized (this){
            String maxParentNum = getTaskCode(surfaceRuptureRepository.getMaxNum());
            surfaceRupture.setDsrId(dsrId).setEvaluateUser(userId).setEvaluateUserName(sUser.getUserName()).setNum(maxParentNum).setSourceDepth(vo.getSourceDepth()).setGeom("POINT("+longitude+" "+latitude+")")
                    .setEvaluateTime(new Date()).setDataSource("1").setLongitude(longitude).setLatitude(latitude).setRuptureLength(BigDecimal.ZERO).setFaultProperties(vo.getFaultProperties()+"")
                    .setDisplacement(BigDecimal.ZERO).setRuptureWidth(BigDecimal.ZERO).setLengthSection("").setProvince(province).setFaultVersion(vo.getFaultVersion()).setEarthQuakeLevel(vo.getEarthQuakeLevel())
                    .setCity(city).setCounty(county).setProvinceId(provinceId).setCityId(cityId).setCountyId(countyId).setDelFlag(YNEnum.N.toString()).setEarthQuakeTime(new Date()).setSourceFrom("2");
            surfaceRuptureRepository.evaluate(Arrays.asList(surfaceRupture));
        }
        return dsrId;
    }


    @Override
    public String hasEvaluateResult(String dsrId) {
        SurfaceRupture byId = surfaceRuptureRepository.getById(dsrId);
        Integer num = surfaceRuptureRepository.hasEvaluateResult(byId.getNum());
        return num>0?"":"评估记录没有评估结果";
    }

    @Override
    public SurfaceRupture getSurfaceRuptureById(String dsrId) {
        SurfaceRupture surfaceRupture = surfaceRuptureRepository.getById(dsrId);
        return surfaceRupture;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveParam(ParamVO paramVO) throws Exception{
        try{
            paramVO.setId(UUIDGenerator.getUUID());
            paramVO.setUserId(PlatformObjectUtils.isNotEmpty(PlatformSessionContext.getUserID())?PlatformSessionContext.getUserID():"c8f1ba6c7cf842409aba43206e9f7442");
            paramVO.setSaveTime(new Date());
            surfaceRuptureRepository.deleteParam();
            surfaceRuptureRepository.saveParam(paramVO);
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("保存失败");
        }
    }

    @Override
    public ParamVO getParam() {
        return surfaceRuptureRepository.getParam();
    }

    @Override
    public RestResponse uploadSingleBvInformation(MultipartFile file) throws Exception {
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        List<Object> title = reader.readRow(0);
        String titleName = "[序号, 省份, 参考位置, 经度, 纬度, 震级, 地表破裂带长度(KM), 发震时间]";
        System.out.println("title.toString() = " + title.toString());
        if (!titleName.equals(title.toString())) {
            return RestResponse.fail("导入失败，请检查表头是否改动");
        }
        List<List<Object>> read = reader.read(2, reader.getRowCount());
        if (read.size() == 0) {
            return RestResponse.fail("导入失败，表格中无数据");
        }
        //数据校验
        RestResponse rs = check(read.size(), read);
        if (rs.getCode() != 200) {
            return RestResponse.fail(rs.getMessage());
        }
        for (List<Object> objects : read) {
            SurfaceRupture entity = new SurfaceRupture();
            entity.setDsrId(UUIDGenerator.getUUID());
            entity.setProvince(objects.get(1).toString());
            entity.setDistrict(objects.get(2).toString());
            entity.setLongitude(new BigDecimal(objects.get(3).toString()));
            entity.setLatitude(new BigDecimal(objects.get(4).toString()));
            entity.setEarthQuakeLevel(new BigDecimal(objects.get(5).toString()));
            entity.setRuptureLength(new BigDecimal(objects.get(6).toString()));
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String str = objects.get(7).toString();
            Date parsedDate = dateFormat.parse(str);
            entity.setEarthQuakeTime(parsedDate);
            try{
                surfaceRuptureRepository.save(entity);
            }catch (Exception e){
                e.printStackTrace();
            }

        }
        return RestResponse.succeed("上传成功!");
    }

    private RestResponse check(int size, List<List<Object>> data) {
        for (int i = 0; i < size; i++) {
            List<Object> objects = data.get(i);
            if (StringUtils.isBlank(objects.get(1).toString())) {
                return RestResponse.fail("第" + (i + 1) + "行的{省份}不能为空！");
            }
            if (StringUtils.isBlank(objects.get(2).toString())) {
                return RestResponse.fail("第" + (i + 1) + "行的{参考位置}不能为空！");
            }
            if (StringUtils.isBlank(objects.get(3).toString())) {
                return RestResponse.fail("第" + (i + 1) + "行的{经度}不能为空！");
            }
            if (StringUtils.isBlank(objects.get(4).toString())) {
                return RestResponse.fail("第" + (i + 1) + "行的{纬度}不能为空！");
            }
            if (StringUtils.isBlank(objects.get(5).toString())) {
                return RestResponse.fail("第" + (i + 1) + "行的{震级}不能为空！");
            }
            if (StringUtils.isBlank(objects.get(6).toString())) {
                return RestResponse.fail("第" + (i + 1) + "行的{地表破裂带长度}不能为空！");
            }
            if (StringUtils.isBlank(objects.get(7).toString())) {
                return RestResponse.fail("第" + (i + 1) + "行的{发震时间}不能为空！");
            }
        }
        return RestResponse.succeed();
    }
}
